package com.soup.bytebuddy.threadpooladvice;

import com.soup.bytebuddy.advice.targets.Cooker;
import com.soup.bytebuddy.advice.targets.Cooker2;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.ClassFileLocator;
import net.bytebuddy.dynamic.loading.ByteArrayClassLoader;
import net.bytebuddy.matcher.ElementMatchers;

import java.lang.reflect.Constructor;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 〈一句话功能简述〉<br>
 *
 * @author zhaoyi
 * @date 2021-04-12 22:18
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public class ThreadPoolAdvice {

    public static ThreadPoolAdvice INSTANCE = new ThreadPoolAdvice();

    ClassLoader classLoader;

    /**
     * 加载未被修改的类
     */
    public void initClassLoader() throws Exception {
        classLoader = new ByteArrayClassLoader.ChildFirst(
                getClass().getClassLoader(),
                ClassFileLocator.ForClassLoader.readToNames(ThreadPoolExecutor.class),
                ByteArrayClassLoader.PersistenceHandler.MANIFEST);
    }

    public void modifyTarget() throws Exception {
        ByteBuddyAgent.install();
        new AgentBuilder.Default()
                .with(AgentBuilder.PoolStrategy.Default.EXTENDED)
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .type(ElementMatchers.is(ThreadPoolExecutor.class), ElementMatchers.is(classLoader))
                .transform((builder, typeDescription, classLoader, module) -> {
                    return builder.visit(Advice.to(ThreadPoolAdviceLogic.class).on(ElementMatchers.isConstructor()));
                })
                .installOnByteBuddyAgent();
    }

    public void print() throws Exception {
        Class<ThreadPoolExecutor> executor = (Class<ThreadPoolExecutor>) classLoader.loadClass(ThreadPoolExecutor.class.getName());
        Constructor<ThreadPoolExecutor> constructor = executor.getDeclaredConstructor(Integer.class, Integer.class, Long.class, TimeUnit.class, BlockingQueue.class, ThreadFactory.class, RejectedExecutionHandler.class);
        constructor.newInstance(1, 1, 5000L,
                TimeUnit.MILLISECONDS, new PriorityBlockingQueue<>(),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    }

    public static void main(String[] args) throws Exception {
        System.setSecurityManager(null);
        INSTANCE.initClassLoader();
        INSTANCE.modifyTarget();
        INSTANCE.print();
    }
}
